package com.example.codegen;

import com.example.utils.CJUtils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

public class Type implements AstNode {
    public String type;
    public int dimension;

    public static boolean disableInterface = true;
    public static HashSet<String> classSet = new HashSet<>();

    static {
        classSet.add("void");
        classSet.add("byte");
        classSet.add("char");
        classSet.add("boolean");
        classSet.add("short");
        classSet.add("int");
        classSet.add("float");
        classSet.add("double");
        classSet.add("long");
        classSet.add("String");
        classSet.add("java_lang_Object");
    }

    public Type(String typeName, int dimensions) {
        if (disableInterface && !classSet.contains(typeName)) {
            typeName = "java_lang_Object";
        }
        this.type = typeName;
        this.dimension = dimensions;
    }

    public static String toJavaType(String type) {
        switch (type) {
            case "java_lang_Object":
                return "Object";
            default:
                return type;
        }
    }

    public String toJava() {
        return toJavaType(type) + "[]".repeat(dimension);
    }

    public static String toGOType(String type) {
        // byte, char, boolean, short, int, float, double, long, void
        switch (type) {
            case "byte":
                return "byte";
            case "char":
                return "rune";
            case "boolean":
                return "bool";
            case "short":
                return "int16";
            case "int":
                return "int";
            case "float":
                return "float32";
            case "double":
                return "float64";
            case "long":
                return "int64";
            case "void":
                return "";
            case "String":
                // just for handmake mop, not for real generated code
                return "string";
//            case "java_lang_Object":
//                return "interface{}";
            default:
                return type.toUpperCase();
        }
    }

    public static boolean goPrimitive(String type) {
        // byte, char, boolean, short, int, float, double, long, void
        switch (type) {
            case "byte":
            case "char":
            case "boolean":
            case "short":
            case "int":
            case "float":
            case "double":
            case "long":
            case "void":
//            case "java_lang_Object":
//                return true;
            case "String":
                // just for handmake mop, not for real generated code
                return true;
            default:
                return false;
        }
    }

    public String toGo() {
        String goType = toGOType(type);
        if (goType.equals("")) {
            return "";
        } else {
            return "[]".repeat(dimension) + (goPrimitive(type) ? "" : "*") + goType;
        }
    }

    @Override
    public String toJs() {
        return type + "[]".repeat(dimension);
    }

    public static String toCSharpType(String type) {
        // byte, char, boolean, short, int, float, double, long, void
        switch (type) {
            case "byte":
                return "byte";
            case "char":
                return "char";
            case "boolean":
                return "bool";
            case "short":
                return "short";
            case "int":
                return "int";
            case "float":
                return "float";
            case "double":
                return "double";
            case "long":
                return "long";
            case "void":
                return "void";
            case "String":
                return "String";
            case "java_lang_Object":
                return "Object";
            default:
                return type.replace('$', '_');
        }
    }


    @Override
    public String toCSharp() {
        return toCSharpType(type) + "[]".repeat(dimension);
    }

    public static String toCJType(String type){
        Map<String, String> map = new HashMap<>();
        map.put("byte", "Byte");
        map.put("char", "Char");
        map.put("boolean", "Bool");
        map.put("short", "Int8");
        map.put("int", "Int64");
        map.put("float", "Float32");
        map.put("double", "Float64");
        map.put("long", "Int64");
        map.put("void", "Unit");
        map.put("null", "None");
        map.put("", "");
        String res = type;
        if(map.containsKey(res))
            res = map.get(res);
        if(CJUtils.defaultValue.containsKey(res))
            return res;
        return "?" + res;
    }

    public String toCJ(){
        String typeTem = type;
        if(type.equals("java_lang_Object"))
            typeTem = "Object";
        String res = toCJType(typeTem);
        for (int i = 0; i < dimension; i++) {
            res = "?Array<" + res + ">";
        }
        return res;
    }
}
